#include "zen_vap_mesh.h"

namespace Zen { namespace Vap {
	
	MeshesCache * MeshesCache::Get()
	{
		static auto me = new MeshesCache;
		return me;
	}
	
	MeshLoader * MeshLoader::Get() {
		static auto me = new MeshLoader;
		return me;
	}
	MeshLoader::MeshLoader()
	{
	}
	SharedMesh MeshLoader::createMeshCubeNoBind(float r)
	{
		auto mesh = std::make_shared<Mesh>();
		static const size_t FN = 6; // faces count
		static const size_t VN = 8; // vertexes count
		static const size_t VCount = FN*4; // 6 faces, 4 vertexes each.
		
		Vec3 verts[VN] = {
			{ -r, -r, +r }, // 0
			{ +r, -r, +r }, // 1
			{ -r, +r, +r }, // 2
			{ +r, +r, +r }, // 3
			
			{ -r, +r, -r }, // 4
			{ +r, +r, -r }, // 5
			{ -r, -r, -r }, // 6
			{ +r, -r, -r }, // 7
		};
		/// 6 faces, 4 vertexes each.
		/// value is index of `verts` `colors`
		int vi[VCount] = {
			0, 1, 2, 3,  // front 0->x+
			4, 5, 6, 7,  // back
			0, 2, 6, 4,  // left 0->y+
			7, 5, 1, 3,  // right
			0, 6, 1, 7,  // bot 0->z-
			3, 5, 2, 4,  // top
		};
		
		/// value is index of `mesh->coords`
		mesh->indexes = {
			0, 1, 2, 2, 1, 3,
			4, 5, 6, 6, 5, 7,
			8, 9, 10, 10, 9, 11,
			12, 13, 14, 14, 13, 15,
			16, 17, 18, 18, 17, 19,
			20, 21, 22, 22, 21, 23,
		};
		
		mesh->coords.reserve(VCount);

		for(size_t i = 0; i < VCount; ++i) {
			mesh->coords.push_back(verts[vi[i]]);
		}
		return mesh;
	}
	
	SharedMesh MeshLoader::createMeshCubeColored(float r)
	{
		auto mesh = createMeshCubeNoBind();

		Color4f colors[7] = {
			eColor::Red,
			eColor::Orange,
			eColor::Yellow,
			eColor::Green,
			eColor::Cyan,
			eColor::Blue,
			eColor::Magenta,
		};

		for(size_t i = 0; i < mesh->coords.size(); ++i) {
			mesh->colors.push_back(colors[i%7]);
		}
		/// fix color
		for(int i = 0; i < mesh->colors.size(); i += 4) {
			auto mc = Zen::Color4fLerp(mesh->colors[i+1], mesh->colors[i+2], 0.5f);
			mesh->colors[i+3] = Zen::Color4fLerp(mesh->colors[i], mc, 2.f);
		}
		return mesh;
		
	}
	SharedMesh MeshLoader::createMeshCubeSameface(float r)
	{
		auto mesh = createMeshCubeColored();
		
		mesh->tex_coords = {
			{ 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 },
			{ 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 },
			{ 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 },
			{ 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 },
			{ 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 },
			{ 0, 1 }, { 1, 1 }, { 0, 0 }, { 1, 0 },
		};
		return mesh;
	}
	
	SharedMesh MeshLoader::createMeshCubeSkybox(float r, bool compressed)
	{
		auto mesh = createMeshCubeColored();

		if(!compressed)
		{
			float x0 = 0, x1 = 0.25f, x2 = 0.5f, x3 = 0.75f, x4 = 1.f;
			float y0 = 0, y1 = 1.f/3, y2 = 2.f/3, y3 = 1.f;

			mesh->tex_coords = {
				{x1, y2}, {x2, y2}, {x1, y1}, {x2, y1},
				{x4, y1}, {x3, y1}, {x4, y2}, {x3, y2},
				{x1, y2}, {x1, y1}, {x0, y2}, {x0, y1},
				{x3, y2}, {x3, y1}, {x2, y2}, {x2, y1},
				{x1, y2}, {x1, y3}, {x2, y2}, {x2, y3},
				{x2, y1}, {x2, y0}, {x1, y1}, {x1, y0},
			};
		}
		else
		{
			float x0 = 0, x1 = 0.5f, x2 = 1.f;
			float y0 = 0, y1 = 1.f/3, y2 = 2.f/3, y3 = 1.f;

			mesh->tex_coords = {
				{ x0, y2 }, {x1, y2}, {x0, y1}, {x1, y1},
				{ x2, y2 }, {x2, y1}, {x1, y2}, {x1, y1},
				{ x1, y3 }, {x2, y3}, {x1, y2}, {x2, y2},
				{ x1, y1 }, {x2, y1}, {x1, y0}, {x2, y0},
				{ x0, y2 }, {x0, y3}, {x1, y2}, {x1, y3},
				{ x1, y1 }, {x1, y0}, {x0, y1}, {x0, y0},
//				{ x, y }, {x, y}, {x, y}, {x, y},
			};
		}

		return mesh;
	}
}}
